//
// Created by alexander on 2/20/19.
//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libavcodec/avcodec.h>
#include <libavutil/opt.h>
#include <libavutil/imgutils.h>

#include </home/alexander/CLionProjects/FFmpegLogTest/log/log.h>
#include "encodevideo.h"

int encodeVideo(const char *outputFileName, const char *codecName)
{
    const AVCodec *avCodec;
    AVCodecContext *avCodecContext = NULL;
    int i, returnCode, x, y, got_output;
    FILE *outputFile;
    AVFrame *avFrame;
    AVPacket avPacket;
    uint8_t endcode[] = {0, 0, 1, 0xb7};

    avcodec_register_all();

    /**查找编码器*/
    avCodec = avcodec_find_encoder_by_name(codecName);
    if(!avCodec)
    {
        logError("Codec not found!\n", "");
        exit(1);
    }

    avCodecContext = avcodec_alloc_context3(avCodec);
    if(!avCodecContext)
    {
        logError("Could not allocate video codec context!\n", "");
        exit(1);
    }

    /**给编码器设置参数*/
    avCodecContext->bit_rate = 400000;
    avCodecContext->width = 352;
    avCodecContext->height = 288;
    /**时间基和帧率*/
    avCodecContext->time_base = (AVRational){1, 25};
    avCodecContext->framerate = (AVRational){25, 1};
    /**gop: 多少帧之后产生一个关键帧（I帧）*/
    avCodecContext->gop_size = 10;
    avCodecContext->max_b_frames = 1;
    avCodecContext->pix_fmt = AV_PIX_FMT_YUV420P;

    if(avCodec->id == AV_CODEC_ID_H264)
    {
        av_opt_set(avCodecContext->priv_data, "preset", "slow", 0);
    }

    /**打开编码器*/
    returnCode = avcodec_open2(avCodecContext, avCodec, NULL);
    if(returnCode < 0)
    {
        logError("Could not open codec!\n", "");
        exit(1);
    }

    outputFile = fopen(outputFileName, "wb");
    if(!outputFile)
    {
        logError("Could not open %s!\n", outputFileName);
        exit(1);
    }

    avFrame = av_frame_alloc();
    if(!avFrame)
    {
        logError("Could not allocate video frame!\n", "");
        exit(1);
    }

    avFrame->format = avCodecContext->pix_fmt;
    avFrame->width = avCodecContext->width;
    avFrame->height = avCodecContext->height;

    returnCode = av_frame_get_buffer(avFrame, 32);
    if(returnCode < 0)
    {
        logError("Could not allocate the video frame data!\n", "");
        exit(1);
    }

    /**编码一秒的视频数据*/
    for (int j = 0; j < 250; j++)
    {
        av_init_packet(&avPacket);
        avPacket.data = NULL;
        avPacket.size = 0;

        fflush(stdout);

        /**确实数据帧可以被写入*/
        returnCode = av_frame_make_writable(avFrame);
        if(returnCode < 0)
        {
            logError("The frame data could not writeable!\n", "");
            exit(1);
        }

        /**造数据*/
        for (y = 0; y < avCodecContext->height; y++)
        {
            for (x = 0; x < avCodecContext->width; ++x)
            {
                avFrame->data[0][y * avFrame->linesize[0] + x] = x + y + i * 3;
            }
        }

        for (y = 0; y < avCodecContext->height / 2; y++)
        {
            for (x = 0; x < avCodecContext->width / 2; x++)
            {
                avFrame->data[1][y * avFrame->linesize[1] + x] = 128 + y + i * 2;
                avFrame->data[2][y * avFrame->linesize[2] + x] = 64 + y + i * 5;
            }
        }

        avFrame->pts = i;

        /**编码图片*/
        returnCode = avcodec_encode_video2(avCodecContext, &avPacket, avFrame, &got_output);
        if(returnCode < 0)
        {
            logError("Error encoding frame!\n", "");
            exit(1);
        }

        if(got_output)
        {
            printf("Write frame %3d (size=%5d)\n", i, avPacket.size);
            fwrite(avPacket.data, 1, avPacket.size, outputFile);
            av_packet_unref(&avPacket);
        }
    }

    /**写入数据*/
    for (got_output = 1;  got_output; i++)
    {
        fflush(stdout);

        returnCode = avcodec_encode_video2(avCodecContext, &avPacket, NULL, &got_output);
        if(returnCode < 0)
        {
            logError("Error encoding frame!\n", "");
            exit(1);
        }

        if(got_output)
        {
            printf("Write frame %3d (size=%5d)\n", i, avPacket.size);
            fwrite(avPacket.data, 1, avPacket.size, outputFile);
            av_packet_unref(&avPacket);
        }
    }

    /**添加结束标志*/
    fwrite(endcode, 1, sizeof(endcode), outputFile);
    fclose(outputFile);

    avcodec_free_context(&avCodecContext);
    av_frame_free(&avFrame);


    return 0;
}































